﻿using IdentityModel.Client;
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace ConsoleClient
{
    class Program
    {
        public static void Main(string[] args) => MainAsync().GetAwaiter().GetResult();

        // 主方法分离,以便异步请求
        public static async Task MainAsync()
        {
            Console.Title = "Console Client Credentials Flow";

            var response = await RequestTokenAsync();
            Console.WriteLine("获取到的凭依为:" + response.AccessToken);
            await CallServiceAsync(response.AccessToken);
        }

        // 异步请求凭依,规避阻塞
        static async Task<TokenResponse> RequestTokenAsync()
        {
            var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
            if (disco.IsError) throw new Exception(disco.Error);

            var client = new TokenClient(
                disco.TokenEndpoint,
                "client",
                "secret");

            return await client.RequestClientCredentialsAsync("api1");
        }

        // 使用凭依来调用api
        static async Task CallServiceAsync(string token)
        {
            var client = new HttpClient();
            client.SetBearerToken(token);

            var response = await client.GetAsync("http://localhost:5001/identity");
            if (!response.IsSuccessStatusCode)
            {
                // 请求失败,错误优先原则.
                Console.WriteLine(response.StatusCode);
                return;
            }

            //请求成功
            var content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);;
        }

        /// <summary>
        /// 获取客户端凭依并请求Api
        /// </summary>
        /// <returns></returns>
        public static async Task GetTokenAndRequestApiAsync()
        {
            // 直接使用IdentityModel库通过指定的元数据来找到节点,Identity封装了对源数据的解析,以便我们使用.
            // 这里我们只需要指定源数据的地址即可,就是http://localhost:5000/.well-known/openid-configuration
            var discovery = await DiscoveryClient.GetAsync("http://localhost:5000");

            // 使用TokenClient发起请求,以便获取token,client和secret必须和服务里的值一致,更合理的应该有个生成机制.
            var tokenClient = new TokenClient(discovery.TokenEndpoint, "client", "secret");
            var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1");

            if (tokenResponse.IsError)
            {
                Console.WriteLine(tokenResponse.Error);
                return;
            }

            Console.WriteLine(tokenResponse.Json);


            // 使用获取到的凭依来调用API
            var client = new HttpClient();
            client.SetBearerToken(tokenResponse.AccessToken); //通常把凭依放到请求头里来使用

            var response = await client.GetAsync("http://localhost:5001/identity");
            if (!response.IsSuccessStatusCode)
            {                
                // 请求不成功,错误优先原则
                Console.WriteLine(response.StatusCode);
                return;
            }

            //请求成功
            var content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);

        }
    }
}